<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="alpha"></div>
    <div class="beta"></div>
    <div class="gamma"></div>
    <script>
        // 概述：
        // 面向对象
        // class/constructor
        // extends/super

        // 什么是面向对象
        // 机器语言->汇编语言->低级语言（面向过程）->高级语言（面向对象）->框架->API
        // 面向对象：把一些公共的东西封装起来，通过new直接调用

        // es5
        // 构造函数
        // function Person(name, age) {
        //     this.name = name;
        //     this.age = age;
        // }

        // 原型
        // Person.prototype.showName = function() {
        //     console.log('我叫' + this.name);
        // };
        // Person.prototype.showAge = function() {
        //     console.log('我' + this.age + '岁');
        // };
        // let p = new Person('blue', 18);
        // p.showName();
        // p.showAge();

        // // 继承
        // function Worker(name, age, job) {
        //     Person.call(this, name, age);
        //     this.job = job;
        // }
        // Worker.prototype = new Person();
        // Worker.prototype.constructor = Worker;
        // Worker.prototype.showJob = function() {
        //     console.log('我是做：' + this.job);
        // };
        // let w = new Worker('blue', 18, '打杂的');
        // w.showName();
        // w.showAge();
        // w.showJob();

        // es5中  类===构造函数
        // 类：只要有new  new后面跟着的就是类
        // 构造函数：通过参数，可以传递到函数本身的this身上




        // ES6类的基础语法
        // class Point2 {
        //     // 可以设置默认值
        //     constructor({
        //         name,
        //         age,
        //         behavior
        //     }) {
        //         this.name = name;
        //         this.age = age;
        //         this.behavior = behavior;
        //     }
        //     eat() {
        //         console.log(`我叫${this.name}\n今年${this.age}岁了\n喜欢${this.behavior}`);
        //     }
        // }
        // // 实例对象
        // var p2 = new Point2({
        //     name: '黄蜀郎',
        //     age: 18,
        //     behavior: '去撤硕吃饭'
        // })
        // p2.eat();


        /*
         *es6中 构造函数和类分开
         *class  声明类的关键字
         *只有构造函数和普通函数
         *属性声明在构造函数中
         *对象是可以调用父级方法的
         */


        // 创建类和对象
        // 1. 通过class 关键字创建类, 类名我们还是习惯性定义首字母大写
        // 2. 类里面有个constructor 函数, 可以接受传递过来的参数, 
        // 同时返回实例对象(即this)
        // 3. constructor 函数 只要 new 生成实例时, 就会自动调用这个函数, 
        // 如果我们不写这个函数, 类也会自动生成这个函数
        // 4. 生成实例 new 不能省略
        // 5. 最后注意语法规范, 创建类 类名后面不要加小括号, 
        // 生成实例 类名后面加小括号, 构造函数不需要加function

        // 类中添加方法
        // 1.类的共有属性放到constructor里面
        // 2.类里面所有的函数不需要写function
        // 3.多个函数方法之间不需要添加逗号分隔




        // 取值函数(getter)和存值函数(setter)
        // 与 ES5 一样，在“类”的内部可以使用get和set关键字，对某个属性设置存值函数和取值函数，拦截该属性的存取行为。
        // class Person {
        //     constructor({
        //         name,
        //         age,
        //         value
        //     }) {
        //         this.name = name;
        //         this.age = age;
        //         this.value = value;
        //     }
        //     get prop() {
        //         return this.value;
        //     }
        //     set prop(value) {
        //         console.log(value);
        //     }
        // }
        // let p = new Person({
        //     name: '黄蜀郎',
        //     age: 30,
        //     value: '来了奥'
        // })
        // console.log(p.prop);
        // p.prop = '去撤硕';



        // class Person {
        //     get prop() {
        //         return 'getter';
        //     }
        //     set prop(value) {
        //         console.log('setter:' + value);
        //     }
        // }
        // let inst = new Person();
        // inst.prop = 123; //setter: 123
        // console.log(inst.prop); // 'getter'
        // 上面代码中，prop属性有对应的存值函数和取值函数，因此赋值和读取行为都被自定义了



        // 属性表达式
        // 类的属性名可以采用表达式
        // let methodName = 'shop';
        // class Person {
        //     constructor({
        //             name,
        //             age,
        //             value
        //         }) {
        //             this.name = name;
        //             this.age = age;
        //             this.value = value;
        //         }
        //         [methodName]() {
        //             console.log(this.name + this.value);
        //         }
        // }
        // let p = new Person({
        //     name: '黄蜀郎',
        //     age: 30,
        //     value: '买买买'
        // });
        // p.shop();
        // 上面代码中，Person类的方法名shop，是从表达式得到的



        // class表达式
        // 与函数一样，类也可以使用表达式的形式定义
        // const Myclass = class Me {
        //     get ClassName() {
        //         return Me.name;
        //     }
        // }
        // let cl = new Myclass();
        // console.log(cl.ClassName)
        // 上面代码使用表达式定义了一个类。
        // 需要注意的是，这个类的名字是Me，但是Me只在 Class 的内部可用，指代当前类。
        // 在 Class 外部，这个类只能用MyClass引用

        // let inst = new MyClass();
        // inst.getClassName() // Me
        // Me.name // ReferenceError: Me is not defined
        // 上面代码表示，Me只在Class内部有定义
        // 如果类的内部没用到的话，可以省略Me，也就是可以写成下面的形式。
        // const MyClass = class {}



        // 采用Class表达式，可以写出立即执行的Class的实例
        // let Person = new class {
        //     constructor(name) {
        //         this.name = name;
        //     }
        //     sayName() {
        //         console.log(this.name);
        //     }
        // }('黄蜀郎');
        // Person.sayName();


        // 静态方法
        // 如果在一个方法前，加上static关键字，就表示该方法
        // 不会被实例继承，而是直接通过类来调用，这就称为“静态方法”。
        // class Foo {
        //     static classMethod() {
        //         return 'hello';
        //     }
        // }
        // console.log(Foo.classMethod()); // 'hello'
        // var foo = new Foo();
        // foo.classMethod()
        // TypeError: foo.classMethod is not a function
        // 上面代码中，Foo类的classMethod方法前有static关键字，表明该方法是一个静态方法，
        // 可以直接在Foo类上调用（Foo.classMethod()），而不是在Foo类的实例上调用。
        // 如果在实例上调用静态方法，会抛出一个错误，表示不存在该方法。
        // **如果静态方法包含this关键字，这个this指的是类，而不是实例



        // class Foo {
        //     static bar() {
        //         this.baz();
        //     }
        //     static baz() {
        //         console.log('hello');
        //     }
        //     baz() {
        //         console.log('world');
        //     }
        // }
        // Foo.bar();
        // 上面代码中，静态方法bar调用了this.baz，这里的this指的是Foo类，而不是Foo的实例，
        // 等同于调用Foo.baz。另外，从这个例子还可以看出，静态方法可以与非静态方法重名


        // 父类的静态方法，可以被子类继承
        // class Foo {
        //     static classMethod() {
        //         return 'hello';
        //     }
        // }
        // class Bar extends Foo {}
        // Bar.classMethod() //hello
        // 上面代码中，父类Foo有一个静态方法，子类Bar可以调用这个方法。


        // 静态方法也可以从super对象上调用的
        // class Foo {
        //     static classMethod() {
        //         return 'hello';
        //     }
        // }
        // class Bar extends Foo {
        //     static classMethod() {
        //         return super.classMethod() + ',too'
        //     }
        // }
        // Bar.classMethod();


        // 实例属性的新写法
        // 实例属性除了定义在constructor() 方法里面的this上面， 也可以定义在类的最顶层
        // class IncreasingCounter {
        //     constructor() {
        //         this._count = 0;
        //     }
        //     get value() {
        //         console.log('Getting the current value!');
        //         return this._count;
        //     }
        //     increment() {
        //         this._count++;
        //     }
        // }
        // 上面代码中，实例属性this._count定义在constructor()方法里面。
        //  另一种写法是，这个属性也可以定义在类的最顶层，其他都不变。
        // 和上面做对比
        // class IncreasingCounter {
        //     _count = 0;
        //     get value() {
        //         console.log('Getting the current value!');
        //         return this._count;
        //     }
        //     increment() {
        //         this._count++;
        //     }
        // }
        // 上面代码中，实例属性_count与取值函数value()和increment()方法，处于同一个层级。
        //  这时，不需要在实例属性前面加上this。

        // class foo {
        //     name = '黄蜀郎';
        //     age = 30;
        //     constructor() {}
        // }
        // 上面的代码，一眼就能看出，foo类有两个实例属性，一目了然。
        // 另外，写起来也比较简洁。


        // 静态属性
        // 静态属性指的是 Class 本身的属性， 即Class.propName， 
        // 而不是定义在实例对象（ this） 上的属性。
        // class Foo {}
        // Foo.prop = 1;
        // console.log(Foo.prop);
        // 上面的写法为Foo类定义了一个静态属性prop
        // 目前， 只有这种写法可行， 因为 ES6 明确规定， Class 内部只有静态方法， 没有静态属性。 
        // 现在有一个提案提供了类的静态属性， 写法是在实例属性的前面， 加上static关键字。
        // class MyClass {
        //     static myStaticProp = 12;
        //     constructor() {
        //         console.log(MyClass.myStaticProp);
        //     }
        // }
    </script>
</body>

</html>